package com.hmall.cart.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
//import com.hmall.cart.client.ItemClient;
//import com.hmall.cart.domain.dto.ItemDTO;
import com.hmall.api.dto.ItemDTO;
import com.hmall.cart.config.CartProperties;
import com.hmall.common.exception.BizIllegalException;
import com.hmall.common.utils.BeanUtils;
import com.hmall.common.utils.CollUtils;
import com.hmall.common.utils.UserContext;
import com.hmall.cart.domain.dto.CartFormDTO;
//import com.hmall.cart.domain.dto.ItemDTO;
import com.hmall.cart.domain.po.Cart;
import com.hmall.cart.domain.vo.CartVO;
import com.hmall.cart.mapper.CartMapper;
import com.hmall.cart.service.ICartService;
//import com.hmall.cart.service.IItemService;
import com.hmall.api.client.ItemClient;
import lombok.AllArgsConstructor;
import lombok.RequiredArgsConstructor;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * <p>
 * 订单详情表 服务实现类
 * </p>
 *
 * @author 虎哥
 * @since 2023-05-05
 */
@Service
@RequiredArgsConstructor //所有final字段会自动生成构造函数参数，确保依赖必须通过构造器注入 --通过构造函数注入
public class CartServiceImpl extends ServiceImpl<CartMapper, Cart> implements ICartService {

//    private final IItemService itemService;

//    private final RestTemplate restTemplate;//修饰为常量 确保引用在对象构造后无法被修改,必须要注入值

//    private RestTemplate restTemplate;
//
//    public CartServiceImpl(RestTemplate restTemplate) {//构造器注入 --也可以使用Lombook自动生成构造函数
//        this.restTemplate = restTemplate;
//    }


//    private final DiscoveryClient discoveryClient;

    private final ItemClient itemClient;

    private final CartProperties cartProperties;

    @Override
    public void addItem2Cart(CartFormDTO cartFormDTO) {
        // 1.获取登录用户
        Long userId = UserContext.getUser();

        // 2.判断是否已经存在
        if(checkItemExists(cartFormDTO.getItemId(), userId)){
            // 2.1.存在，则更新数量
            baseMapper.updateNum(cartFormDTO.getItemId(), userId);
            return;
        }
        // 2.2.不存在，判断是否超过购物车数量
        checkCartsFull(userId);

        // 3.新增购物车条目
        // 3.1.转换PO
        Cart cart = BeanUtils.copyBean(cartFormDTO, Cart.class);
        // 3.2.保存当前用户
        cart.setUserId(userId);
        // 3.3.保存到数据库
        save(cart);
    }

    @Override
    public List<CartVO> queryMyCarts() {
        // 1.查询我的购物车列表
        List<Cart> carts = lambdaQuery().eq(Cart::getUserId,UserContext.getUser()).list();

        if (CollUtils.isEmpty(carts)) {
            return CollUtils.emptyList();
        }

        // 2.转换VO
        List<CartVO> vos = BeanUtils.copyList(carts, CartVO.class);

        // 3.处理VO中的商品信息
        handleCartItems(vos);

        // 4.返回
        return vos;
    }

    private void handleCartItems(List<CartVO> vos) {
        Set<Long> itemIds = vos.stream().map(CartVO::getItemId).collect(Collectors.toSet());

        // 2.查询商品  查询的是数据库商品表中的商品而非购物车的商品 一个新一个旧
/*
        // 2.1根据服务的名称获取服务的实例列表
        List<ServiceInstance> instances = discoveryClient.getInstances("item-service");//获取服务实例列表
        if (CollUtils.isEmpty(instances)) {
            return;
        }

        // 2.2手写负载均衡，从实例表中列表中挑选一个实例item-service 随机从0到集合大小的整数中选一个
        // 最终得到一个服务实例instance,里面包含uri 端口等等
        ServiceInstance instance = instances.get(RandomUtil.randomInt(instances.size()));

//        List<ItemDTO> items = itemService.queryItemByIds(itemIds); item-service中的根据id获取ItemDTO方法

        //2.3使用RestTemplate向item-service发送请求(HTTP请求 得到响应)
        ResponseEntity<List<ItemDTO>> response = restTemplate.exchange(  //方法传参 请求的URL地址 HTTP请求的方法 包含请求头和请求体的HttpEntity对象 响应体中数据的Java类型 URL中的变量参数
                instance.getUri()+"/items?ids={ids}",
                HttpMethod.GET,//请求方式和请求路径
                null, //请求实体
                new ParameterizedTypeReference<List<ItemDTO>>() //返回值类型
                {}//直接使用List<ItemDTO>.class会导致泛型的类型擦除
                , Map.of("ids", CollUtil.join(itemIds, ","))//请求参数
        );

        //解析响应
        if (!response.getStatusCode().is2xxSuccessful()) {
            //查询失败 直接结束
            return;
        }
        List<ItemDTO> items = response.getBody();
        通过openFeign简化实现

        //通过FeignClient简化发送请求的这些步骤
        List<ItemDTO> items = itemClient.queryItemByIds(itemIds);

 */
        List<ItemDTO> items = itemClient.queryItemByIds(itemIds);

        if (CollUtils.isEmpty(items)) {
            return;
        }


        // 3.转为 id 到 item的map 这里将将商品的id和新的商品信息(商品表中的信息) 绑定成键值对
        Map<Long, ItemDTO> itemMap = items.stream().collect(Collectors.toMap(ItemDTO::getId, Function.identity()));
        // 4.写入vo
        for (CartVO v : vos) {//基于购物车(旧)中的商品id  查询出itemMap集合中的商品信息(新)
            ItemDTO item = itemMap.get(v.getItemId());
            if (item == null) {
                continue;
            }
            v.setNewPrice(item.getPrice());
            v.setStatus(item.getStatus());
            v.setStock(item.getStock());
        }
    }

    @Override
    public void removeByItemIds(Collection<Long> itemIds) {
        // 1.构建删除条件，userId和itemId
        QueryWrapper<Cart> queryWrapper = new QueryWrapper<Cart>();
        queryWrapper.lambda()
                .eq(Cart::getUserId, UserContext.getUser())
                .in(Cart::getItemId, itemIds);
        // 2.删除
        remove(queryWrapper);
    }

    private void checkCartsFull(Long userId) {
        int count = lambdaQuery().eq(Cart::getUserId, userId).count();
        if (count >= cartProperties.getMaxItems()) {
            throw new BizIllegalException(StrUtil.format("用户购物车课程不能超过{}", cartProperties.getMaxItems()));
        }
    }

    private boolean checkItemExists(Long itemId, Long userId) {
        int count = lambdaQuery()
                .eq(Cart::getUserId, userId)
                .eq(Cart::getItemId, itemId)
                .count();
        return count > 0;
    }
}
